package com.gitee.feizns.web.ex.impl;

import com.gitee.feizns.web.domain.result.Ret;
import com.gitee.feizns.web.ex.CustomizeExceptionHandler;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Path;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/**
 * 方法级校验
 * @author feizns
 * @since 2019/7/19
 */
public class ConstraintViolationExceptionHandler implements CustomizeExceptionHandler<ConstraintViolationException, Object> {

    private static final Set<String> DEFAULT_MESSAGE = new HashSet<>();

    static {
        DEFAULT_MESSAGE.add("javax.validation.constraints");
        DEFAULT_MESSAGE.add("org.hibernate.validator.constraints");
    }

    @Override
    public ResponseEntity<Ret<Object>> handle(ConstraintViolationException e) {
        return badRequest(getMessage(e));
    }

    private ResponseEntity<Ret<Object>> badRequest(String msg) {
        HttpStatus status = HttpStatus.BAD_REQUEST;
        return ResponseEntity.status(status).body(Ret.err(status.value(), msg));
    }

    private String getMessage(ConstraintViolationException e) {
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        for (ConstraintViolation<?> violation : violations) {
            String template = violation.getMessageTemplate();
            if ( isDefault(template) ) {
                String name = getLastName(violation);
                if ( name != null )
                    return String.format("Parameter %s %s.", name, violation.getMessage());
            } else {
                return violation.getMessage();
            }
        }
        return null;
    }

    private boolean isDefault(String template) {
        return DEFAULT_MESSAGE.stream().anyMatch(template::contains);
    }

    private String getLastName(ConstraintViolation<?> violation) {
        Path path = violation.getPropertyPath();
        Iterator<Path.Node> iterator = path.iterator();
        String ret = null;
        while ( iterator.hasNext() ) {
            ret = iterator.next().getName();
        }
        return ret;
    }

}
